﻿using Auto.AlgsAndPush.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace Auto.AlgsAndPush.Services
{
    public class FilterMQHostedService : BackgroundService
    {
        private readonly ILogger _logger;
        private readonly IServiceProvider _serviceProvider;

        private ConnectionFactory _connectionFactory;
        private IConnection _connection;
        private IModel _channel;
        private string _queueName;
        private const string EXCHANGE_NAME = "auto";
        private const string RoutePath = "*.groupresult.*";
        public FilterMQHostedService(ILogger<FilterMQHostedService> logger, IServiceProvider serviceProvider)
        {
            _logger = logger;
            _serviceProvider = serviceProvider;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            // RabbitMQ Connection
            _connectionFactory = new ConnectionFactory { HostName = "localhost" };
            _connection = _connectionFactory.CreateConnection();
            _channel = _connection.CreateModel();

            _channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Topic);
            _queueName = _channel.QueueDeclare().QueueName;
            _channel.QueueBind(_queueName, EXCHANGE_NAME, RoutePath);

            _logger.LogInformation($"Queue [{_queueName}] is waiting for message");
            return base.StartAsync(cancellationToken);
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            stoppingToken.ThrowIfCancellationRequested();


            // listen to RabbitMQ messages
            var consumer = new EventingBasicConsumer(_channel);
            consumer.Received += async (bc, ea) =>
              {
                  _logger.LogInformation($"Revice Massage at {DateTime.Now}");
                  var message = Encoding.UTF8.GetString(ea.Body.ToArray());

                  try
                  {
                      var ret = JsonSerializer.Deserialize<SubProject>(message);
                      // handle MQ
                      using (var scope = _serviceProvider.CreateScope())
                      {
                          var processService = scope.ServiceProvider.GetRequiredService<FilterMQProcessService>();
                          await processService.Start(ret);
                      }
                  }
                  catch (Exception ex)
                  {
                      _logger.LogError($"[Rabbit hosted service], Error:{ex.Message}");
                  }
              };
            _channel.BasicConsume(_queueName, true, consumer);
        }

        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            await base.StopAsync(cancellationToken);
            _connection.Close();
            _logger.LogInformation("RabbitMQ Connection is closed");
        }
    }
}
